package znet

import (
	"fmt"
	"net"
	"io"
	"errors"
	"zinx/ziface"
)

type Connection struct {
	Conn *net.TCPConn
	ConnID uint32
	isClosed bool

	handleAPI ziface.HandleFunc

	Router ziface.IRouter

	ExitBuffChan chan bool

	msgChan chan []byte
}

func NewConnection(conn *net.TCPConn, connId uint32, router ziface.IRouter) *Connection {
	c := &Connection {
		Conn : conn,
		ConnID : connId,
		isClosed : false,
		handleAPI : nil,
		ExitBuffChan : make(chan bool,1),
		Router:router,
		msgChan:make(chan []byte),
	}

	return c
}


func (c *Connection)StartReader() {
	fmt.Println("Reader Goroutine is running")
	defer fmt.Println(c.RemoteAddr().String()," conn reader exit!")
	defer c.Stop()

	for {
		/*
		buf := make([]byte,512)
		_,err := c.Conn.Read(buf)
		if err != nil {
			fmt.Println("recv buf err ",err)
			c.ExitBuffChan <- true
			continue
		}
		
		if err := c.handleAPI(c.Conn,buf,cnt); err != nil {
			fmt.Println("connID ", c.ConnID," handle is error")
			c.ExitBuffChan <- true
			return
		}
		
		req := Request {
			conn:c,
			data:buf,
		}
		go func(request ziface.IRequest) {
			fmt.Println("00000000000",c.Router)
			c.Router.PreHandle(request)
			c.Router.Handle(request)
			c.Router.PostHandle(request)
		}(&req)

		*/
		dp := NewDataPack()
		headData := make([]byte,dp.GetHeadLen())
		if _,err := io.ReadFull(c.GetTCPConnection(),headData); err != nil {
			fmt.Println("read msg head error ",err)
			c.ExitBuffChan <- true
			continue
		}
		msg ,err := dp.Unpack(headData)
		if err != nil {
			fmt.Println("unpack error ",err)
			c.ExitBuffChan <- true
			continue
		}

		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte,msg.GetDataLen())
			if _,err := io.ReadFull(c.GetTCPConnection(),data); err != nil {
				c.ExitBuffChan <- true
				continue
			}
		}
		msg.SetData(data)

		req := Request {
			conn:c,
			msg:msg,
		}

		go func(request ziface.IRequest) {
			c.Router.PreHandle(request)
			c.Router.Handle(request)
			c.Router.PostHandle(request)
		}(&req)
	}
}

func (c* Connection) StartWriter() {
	fmt.Println("[Writer Gorouting is running]")
	defer fmt.Println(c.RemoteAddr().String(),"[conn Writer exit!]")

	for {
		select {
			case data := <- c.msgChan:
				if _,err := c.Conn.Write(data); err != nil {
					fmt.Println("SendData error:", err)
					return
				}
			case <- c.ExitBuffChan:
				return
		}
	}
}

func (c *Connection) SendMsg(msgId uint32,data []byte) error {
	if c.isClosed == true {
		return errors.New("Connection closed when send msg")
	}
	dp := NewDataPack()
	msg,err := dp.Pack(NewMsgPackage(msgId,data))
	if err != nil {
		fmt.Println("Pack error msg id = ",msgId)
		return errors.New("Pack error msg ")
	}

	if _,err := c.Conn.Write(msg); err != nil {
		fmt.Println("Write msg id ",msgId," error ")
		c.ExitBuffChan <- true
		return errors.New("conn Write error")
	}
	return nil
}

func (c* Connection) Start() {
	go c.StartReader()

	for {
		select {
		case <- c.ExitBuffChan:
			return
		}
	}
}

func (c *Connection) Stop() {
	if c.isClosed == true {
		return
	}
	c.isClosed = true

	c.Conn.Close()

	c.ExitBuffChan <- true

	close(c.ExitBuffChan)
}

func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}




